/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../xos/head.h"
#include "file_impl.h"

namespace xos
{
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    static file_impl::ITEM_DATA xos_item_data;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    file_impl::file_impl()
    {
        init_data();
    }

    file_impl::~file_impl()
    {
        term();
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    int file_impl::get_xos_item_data( ITEM_DATA*& item_ptr )
    {
        int ret = 0;
        xos_item_data.set_container( mgr::container() );
        item_ptr = &xos_item_data;
        return ret;
    }

    int file_impl::init_data()
    {
        int nRet = 0;
        m_hFile = -1;
        m_file_name = "";
        m_cTime = 0;
        m_aTime = 0;
        m_mTime = 0;
        return nRet;
    }

    int file_impl::init()
    {
        int nRet = 0;
        return nRet;
    }

    int file_impl::term()
    {
        int nRet = 0;

        close();
        init_data();

        return nRet;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //
    // open a file
    // 
    int file_impl::open( const char* lpszFileName, uint32_t ulAccessFlag, uint32_t ulShareMode, uint32_t ulCreateFlag )
    {
        int nRet = 0;

        uint32_t ulFileFlag = 0;

        // access type

        if( XOS_FILE_READ & ulAccessFlag )
        {
            ulFileFlag |= O_RDONLY;
        }

        if( XOS_FILE_WRITE & ulAccessFlag )
        {
            ulFileFlag |= O_WRONLY | O_RDONLY;
        }

        // create type

        if( ulCreateFlag & XOS_FILE_CREATE )
        {
            ulFileFlag |= O_CREAT;
        }

        // 
        // share type
        // 
        if( ulCreateFlag & XOS_FILE_OPEN )
        {
            ulFileFlag |= 0;
        }

        if( 0 == nRet )
        {
            m_hFile = ::open( lpszFileName, ulFileFlag, 0666 );

            if( -1 == m_hFile )
            {
                nRet = 1;
            }
        }

        return nRet;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    // 
    // get file time
    // 
    int file_impl::get_file_time( int64_t* lpCreateTime, int64_t* lpAccessTime, int64_t* lpModifyTime )
    {
        int nRet = 0;

        struct stat st = { 0 };

        if( (0 == nRet) && (-1 == m_hFile) )
        {
            if( lpCreateTime )
            {
                *lpCreateTime = m_cTime;
            }
            if( lpAccessTime )
            {
                *lpAccessTime = m_aTime;
            }
            if( lpModifyTime )
            {
                *lpModifyTime = m_mTime;
            }
            nRet = 1;
        }

        if( 0 == nRet )
        {
            nRet = fstat( m_hFile, &st );
        }

        if( (0 == nRet) && lpCreateTime )
        {
            *lpCreateTime = st.st_ctime;
            m_cTime = st.st_ctime;
        }

        if( (0 == nRet) && lpAccessTime )
        {
            *lpAccessTime = st.st_atime;
            m_aTime = st.st_atime;
        }

        if( (0 == nRet) && lpModifyTime )
        {
            *lpModifyTime = st.st_mtime;
            m_mTime = st.st_mtime;
        }

        return nRet;
    }

    // 
    // get file or dir name
    // 
    const char* file_impl::get_file_name( char* lpszFileName, int nLen, int* pnLenNeeded )
    {
        if( pnLenNeeded )
        {
            *pnLenNeeded = (int)m_file_name.length();
        }

        if( lpszFileName )
        {
            strcpy( lpszFileName, m_file_name.c_str() );
        }

        return m_file_name.c_str();
    }

    // 
    // move file pointer to ...
    // 
    int file_impl::set_file_pos( enumFilePos enumFrom, int64_t iPos64, int64_t* lpSeek64 )
    {
        int nRet = 0;

        off_t tOffset = iPos64, tSeekRet = -1;
        uint32_t ulType = 0;

        if( 0 == nRet )
        {
            switch( enumFrom )
            {
                case XOS_FILE_POS_BEGIN:
                {
                    ulType = SEEK_SET;
                }
                break;
                case XOS_FILE_POS_CUR:
                {
                    ulType = SEEK_CUR;
                }
                break;
                case XOS_FILE_POS_END:
                {
                    ulType = SEEK_END;
                }
                break;
                default:
                {
                    nRet = 1;
                }
                break;
            }
        }

        if( 0 == nRet )
        {
            if( -1 == m_hFile )
            {
                nRet = 1;
            }
        }

        if( 0 == nRet )
        {
            tSeekRet = lseek( m_hFile, tOffset, ulType );
        }

        if( lpSeek64 )
        {
            *lpSeek64 = tSeekRet;
        }

        return nRet;
    }

    // 
    // get current file pointer
    // 
    int file_impl::get_file_pos( int64_t* lpSize64 )
    {
        int nRet = 0;

        off_t tOffset = 0;

        if( -1 == m_hFile )
        {
            nRet = 1;
        }

        if( 0 == nRet )
        {
            tOffset = lseek( m_hFile, 0, SEEK_CUR );
        }

        if( 0 == nRet )
        {
            *lpSize64 = tOffset;
        }

        return nRet;
    }

    // 
    // get current file pointer
    // 
    int file_impl::get_file_size( int64_t* lpSize64 )
    {
        int nRet = 0;

        struct stat st = { 0 };
        off_t st_size = 0;

        if( -1 == m_hFile )
        {
            nRet = 1;
        }

        if( 0 == nRet )
        {
            fstat( m_hFile, &st );
            st_size = st.st_size;
        }

        if( 0 == nRet )
        {
            *lpSize64 = st_size;
        }

        return nRet;
    }

    // 
    // commit file disk space.
    // 
    int file_impl::commit_file( int64_t iPos64 )
    {
        int nRet = 0;

        off_t st_size = iPos64, st_pos = 0;
        char buf[4096] = { 0 };
        int ret = 0;

        lseek( m_hFile, 0, SEEK_SET );

        while( (-1 != ret) && (st_pos < st_size) )
        {
            off_t len = sizeof( buf );

            if( st_size < st_pos + len )
            {
                len = st_size - st_pos;
            }

            st_pos += len;

            ret = ::write( m_hFile, buf, len );
        }

        lseek( m_hFile, 0, SEEK_SET );

        return nRet;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    // 
    // write file data
    // 
    // -1 means failed. other , write bytes
    // 
    int file_impl::write( const void * lpBuf, uint32_t ulBufSize )
    {
        int nRet = 0;

        if( -1 == m_hFile )
        {
            nRet = -1;
        }

        if( 0 == nRet )
        {
            nRet = ::write( m_hFile, lpBuf, ulBufSize );
        }

        return nRet;
    }

    // 
    // read file data
    // 
    // -1 means failed. other , read bytes
    //
    int file_impl::read( void * lpBuf, uint32_t ulBufSize )
    {
        int nRet = 0;

        if( -1 == m_hFile )
        {
            nRet = -1;
        }

        if( 0 == nRet )
        {
            nRet = ::read( m_hFile, lpBuf, ulBufSize );
        }

        return nRet;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    int file_impl::write( xos_box::i_list * pList )
    {
        int ret = 0;
        xos_box::i_list_iter * pIter = pList->begin();
        xos_box::i_buf * pBuf = 0;
        while( ( pBuf = (xos_box::i_buf *)pIter->next() ) )
        {
            int len = write( pBuf );
            ret += len;
        }
        xos_stl::release_interface( pIter );
        return ret;
    }

    int file_impl::read( xos_box::i_list * pList )
    {
        int ret = 0;
        xos_box::i_buf * pBuf = 0;
        while( 1 )
        {
            pBuf = mgr::container()->box()->buf();
            int len = read( pBuf );
            if( len > 0 )
            {
                pList->push_back( pBuf );
                ret += len;
                pBuf = 0;
            }
            else
            {
                xos_stl::release_interface( pBuf );
                break;
            }
        }
        return ret;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    int file_impl::write( xos_box::i_big_buf * pBuf )
    {
        int nRet = 0;
        int nLen = 0;
        char * lpszBuf = pBuf->get_data( 0, 0, 0, &nLen );
        nRet = write( lpszBuf, (uint32_t)nLen );
        return nRet;
    }

    int file_impl::read( xos_box::i_big_buf * pBuf )
    {
        int nRet = 0;
        int nLen = pBuf->get_len( 0 );
        int nPos = pBuf->get_pos( 0 );
        uint32_t uSize = (uint32_t)( pBuf->get_buf_size( 0 ) - nLen - nPos );
        char * lpszBuf = pBuf->get_data( 0, 0, 0, 0 );
        nRet = read( lpszBuf, uSize );
        if( nRet > 0 )
        {
            nLen += nRet;
            pBuf->set_len( nLen );
        }
        return nRet;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    int file_impl::write( xos_box::i_buf * pBuf )
    {
        int nRet = 0;
        int nLen = 0;
        char * lpszBuf = pBuf->get_data( 0, 0, 0, &nLen );
        nRet = write( lpszBuf, (uint32_t)nLen );
        return nRet;
    }

    int file_impl::read( xos_box::i_buf * pBuf )
    {
        int nRet = 0;
        int nLen = pBuf->get_len( 0 );
        int nPos = pBuf->get_pos( 0 );
        uint32_t uSize = (uint32_t)( pBuf->get_buf_size( 0 ) - nLen - nPos );
        char * lpszBuf = pBuf->get_data( 0, 0, 0, 0 );
        nRet = read( lpszBuf, uSize );
        if( nRet > 0 )
        {
            nLen += nRet;
            pBuf->set_len( nLen );
        }
        return nRet;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    // 
    // close file handle
    //  
    int file_impl::close()
    {
        int nRet = 0;

        if( -1 != m_hFile )
        {
            ::close( m_hFile );
            m_hFile = -1;
        }

        return nRet;
    }
} // xos
